{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "# CRNN-CTC 验证码识别"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "😋😋公众号算法美食屋后台回复关键词：**torchkeras**，获取本文notebook源代码和数据集下载链接。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "本范例我们使用经典的 CRNN+ CTC Loss 的OCR模型来识别验证码。\n",
    "\n",
    "我们通过导入一个叫 [captcha](https://github.com/lepture/captcha/) 的库来生成验证码。\n",
    "\n",
    "我们生成验证码的字符由数字和大写字母组成。\n",
    "\n",
    "项目参考： https://github.com/ypwhs/captcha_break \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "#!pip install captcha torchkeras "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-06-18T11:19:45.698786Z",
     "start_time": "2019-06-18T11:19:45.381128Z"
    }
   },
   "outputs": [],
   "source": [
    "import torch \n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "from torchvision.transforms.functional import to_tensor, to_pil_image\n",
    "\n",
    "from tqdm import tqdm\n",
    "import random\n",
    "import numpy as np\n",
    "\n",
    "import torchkeras \n",
    "from pathlib import Path\n",
    "from collections import OrderedDict \n",
    "\n",
    "\n",
    "characters = '-' + '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'  # 注：’-‘ 为[blank] 特殊字符\n",
    "width, height  = 192, 64\n",
    "n_classes = len(characters)\n",
    "\n",
    "txt_length = 4 #识别的验证码长度\n",
    "seq_length = 12 #CRNN输出序列长度，一般要求 seq_length>=2*txt_length+1 \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 一，准备数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<PIL.Image.Image image mode=RGB size=320x64>"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from captcha.image import ImageCaptcha\n",
    "generator = ImageCaptcha(width=320, height=64, \n",
    "        fonts=[str(Path(torchkeras.__file__).parent/'assets'/'SimHei.ttf') ],\n",
    "        font_sizes=[40,45])\n",
    "generator.generate_image('中国人民很行')\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-06-18T11:19:45.704071Z",
     "start_time": "2019-06-18T11:19:45.700019Z"
    }
   },
   "outputs": [],
   "source": [
    "class CaptchaDataset(Dataset):\n",
    "    def __init__(self, characters, length, \n",
    "                 width, height, input_length, label_length):\n",
    "        super(CaptchaDataset, self).__init__()\n",
    "        self.characters = characters\n",
    "        self.length = length\n",
    "        self.width = width\n",
    "        self.height = height\n",
    "        self.input_length = input_length\n",
    "        self.label_length = label_length\n",
    "        self.n_class = len(characters)\n",
    "        self.generator = ImageCaptcha(width=width, height=height)\n",
    "\n",
    "    def __len__(self):\n",
    "        return self.length\n",
    "    \n",
    "    def __getitem__(self, index):\n",
    "        random_str = ''.join([random.choice(self.characters[1:]) for j in range(self.label_length)])\n",
    "        image = to_tensor(self.generator.generate_image(random_str))\n",
    "        target = torch.tensor([self.characters.find(x) for x in random_str], dtype=torch.long)\n",
    "        input_length = torch.full(size=(1, ), fill_value=self.input_length, dtype=torch.long)\n",
    "        target_length = torch.full(size=(1, ), fill_value=self.label_length, dtype=torch.long)\n",
    "        return image, target, input_length, target_length\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-06-18T11:19:45.737300Z",
     "start_time": "2019-06-18T11:19:45.735033Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "FA6Z tensor([12]) tensor([4])\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<PIL.Image.Image image mode=RGB size=192x64>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "batch_size = 128\n",
    "ds_train= CaptchaDataset(characters, 100 * batch_size, \n",
    "                         width, height, seq_length, txt_length)\n",
    "\n",
    "ds_val = CaptchaDataset(characters, 20 * batch_size, \n",
    "                        width, height, seq_length, txt_length)\n",
    "\n",
    "dl_train = DataLoader(ds_train, batch_size=batch_size, num_workers=4)\n",
    "dl_val = DataLoader(ds_val, batch_size=batch_size, num_workers=4)\n",
    "\n",
    "\n",
    "ds_test = CaptchaDataset(characters, 1, width, height, seq_length, txt_length)\n",
    "\n",
    "image, target, input_length, label_length = ds_test[0]\n",
    "print(''.join([characters[x] for x in target]), input_length, label_length)\n",
    "to_pil_image(image)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  二，定义模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-06-18T11:19:45.744324Z",
     "start_time": "2019-06-18T11:19:45.738366Z"
    }
   },
   "outputs": [],
   "source": [
    "class CRNN(nn.Module):\n",
    "    def __init__(self, n_classes, input_shape=(3, 64, 128)):\n",
    "        super().__init__()\n",
    "        self.input_shape = input_shape\n",
    "        channels = [32, 64, 128, 256, 256]\n",
    "        layers = [2, 2, 2, 2, 2]\n",
    "        kernels = [3, 3, 3, 3, 3]\n",
    "        pools = [2, 2, 2, 2, (2, 1)]\n",
    "        modules = OrderedDict()\n",
    "        \n",
    "        def cba(name, in_channels, out_channels, kernel_size):\n",
    "            modules[f'conv{name}'] = nn.Conv2d(in_channels, out_channels, kernel_size,\n",
    "                                               padding=(1, 1) if kernel_size == 3 else 0)\n",
    "            modules[f'bn{name}'] = nn.BatchNorm2d(out_channels)\n",
    "            modules[f'relu{name}'] = nn.ReLU(inplace=True)\n",
    "        \n",
    "        last_channel = 3\n",
    "        for block, (n_channel, n_layer, n_kernel, k_pool) in enumerate(zip(channels, layers, kernels, pools)):\n",
    "            for layer in range(1, n_layer + 1):\n",
    "                cba(f'{block+1}{layer}', last_channel, n_channel, n_kernel)\n",
    "                last_channel = n_channel\n",
    "            modules[f'pool{block + 1}'] = nn.MaxPool2d(k_pool)\n",
    "        modules[f'dropout'] = nn.Dropout(0.25, inplace=True)\n",
    "        \n",
    "        self.cnn = nn.Sequential(modules)\n",
    "        self.lstm = nn.LSTM(input_size=self.infer_features(), hidden_size=128, num_layers=2, bidirectional=True)\n",
    "        self.fc = nn.Linear(in_features=256, out_features=n_classes)\n",
    "    \n",
    "    def infer_features(self):\n",
    "        x = torch.zeros((1,)+self.input_shape)\n",
    "        x = self.cnn(x)\n",
    "        x = x.reshape(x.shape[0], -1, x.shape[-1])\n",
    "        return x.shape[1]\n",
    "    \n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.cnn(x)\n",
    "        x = x.reshape(x.shape[0], -1, x.shape[-1])\n",
    "        x = x.permute(2, 0, 1)\n",
    "        x, _ = self.lstm(x)\n",
    "        x = self.fc(x)\n",
    "        return x\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([12, 32, 37])\n"
     ]
    }
   ],
   "source": [
    "net = CRNN(n_classes, input_shape=(3, height, width))\n",
    "inputs = torch.zeros((32, 3, height, width))\n",
    "outputs = net(inputs)\n",
    "print(outputs.shape) # LSTM默认输出的形状是 Length在前\n",
    "net.cuda();\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 三， 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-06-18T11:19:48.052899Z",
     "start_time": "2019-06-18T11:19:48.041088Z"
    }
   },
   "outputs": [],
   "source": [
    "# 解码函数和计算准确率函数\n",
    "\n",
    "def decode_target(sequence):\n",
    "    return ''.join([characters[x] for x in sequence]).replace(' ', '')\n",
    "\n",
    "def decode(sequence):\n",
    "    a = ''.join([characters[x] for x in sequence])\n",
    "    s = ''.join([x for j, x in enumerate(a[:-1]) if x != characters[0] and x != a[j+1]])\n",
    "    if len(s) == 0:\n",
    "        return ''\n",
    "    if a[-1] != characters[0] and s[-1] != a[-1]:\n",
    "        s += a[-1]\n",
    "    return s\n",
    "\n",
    "\n",
    "def eval_acc(targets, preds):\n",
    "    preds_argmax = preds.detach().permute(1, 0, 2).argmax(dim=-1)\n",
    "    targets = targets.cpu().numpy()\n",
    "    preds_argmax = preds_argmax.cpu().numpy()\n",
    "    a = np.array([decode_target(gt) == decode(pred) for gt,\n",
    "                  pred in zip(targets, preds_argmax)])\n",
    "    return a.mean()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch.nn.functional as F \n",
    "from torchkeras import KerasModel\n",
    "\n",
    "#我们覆盖KerasModel的StepRunner以实现自定义训练逻辑。\n",
    "#注意这里把acc指标的结果写在了step_loss中以便和loss一样在Epoch上求平均，这是一个非常灵活而且有用的写法。\n",
    "\n",
    "class StepRunner:\n",
    "    def __init__(self, net, loss_fn, accelerator, stage = \"train\", metrics_dict = None, \n",
    "                 optimizer = None, lr_scheduler = None\n",
    "                 ):\n",
    "        self.net,self.loss_fn,self.metrics_dict,self.stage = net,loss_fn,metrics_dict,stage\n",
    "        self.optimizer,self.lr_scheduler = optimizer,lr_scheduler\n",
    "        self.accelerator = accelerator\n",
    "        if self.stage=='train':\n",
    "            self.net.train() \n",
    "        else:\n",
    "            self.net.eval()\n",
    "    \n",
    "    def __call__(self, batch):\n",
    "        \n",
    "        images, targets, input_lengths, target_lengths = batch\n",
    "        \n",
    "        #loss\n",
    "        preds = self.net(images)\n",
    "        preds_log_softmax = F.log_softmax(preds, dim=-1)\n",
    "        loss = F.ctc_loss(preds_log_softmax, targets, input_lengths, target_lengths)\n",
    "        acc = eval_acc(targets,preds)\n",
    "            \n",
    "\n",
    "        #backward()\n",
    "        if self.optimizer is not None and self.stage==\"train\":\n",
    "            self.accelerator.backward(loss)\n",
    "            self.optimizer.step()\n",
    "            if self.lr_scheduler is not None:\n",
    "                self.lr_scheduler.step()\n",
    "            self.optimizer.zero_grad()\n",
    "            \n",
    "            \n",
    "        all_loss = self.accelerator.gather(loss).sum()\n",
    "        \n",
    "        #losses\n",
    "        step_losses = {self.stage+\"_loss\":\n",
    "                       all_loss.item(),\n",
    "                       self.stage+'_acc':acc}\n",
    "        \n",
    "        #metrics\n",
    "        step_metrics = {}\n",
    "        if self.stage==\"train\":\n",
    "            if self.optimizer is not None:\n",
    "                step_metrics['lr'] = self.optimizer.state_dict()['param_groups'][0]['lr']\n",
    "            else:\n",
    "                step_metrics['lr'] = 0.0\n",
    "        return step_losses,step_metrics\n",
    "    \n",
    "    \n",
    "KerasModel.StepRunner = StepRunner \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-06-18T12:18:50.675432Z",
     "start_time": "2019-06-18T11:19:48.053976Z"
    }
   },
   "outputs": [],
   "source": [
    "\n",
    "\n",
    "model = KerasModel(net,\n",
    "                   loss_fn=None,\n",
    "                   optimizer = torch.optim.AdamW(net.parameters(),lr = 2e-6)\n",
    "                   )\n",
    "\n",
    "model.load_ckpt('ctc_crnn.pt')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-06-18T12:18:50.675432Z",
     "start_time": "2019-06-18T11:19:48.053976Z"
    },
    "code_folding": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[0;31m<<<<<< ⚡️ cuda is used >>>>>>\u001b[0m\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 600x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "\n",
       "<style>\n",
       "    /* background: */\n",
       "    progress::-webkit-progress-bar {background-color: #CDCDCD; width: 100%;}\n",
       "    progress {background-color: #CDCDCD;}\n",
       "\n",
       "    /* value: */\n",
       "    progress::-webkit-progress-value {background-color: #00BFFF  !important;}\n",
       "    progress::-moz-progress-bar {background-color: #00BFFF  !important;}\n",
       "    progress {color: #00BFFF ;}\n",
       "\n",
       "    /* optional */\n",
       "    .progress-bar-interrupted, .progress-bar-interrupted::-webkit-progress-bar {\n",
       "        background: #000000;\n",
       "    }\n",
       "</style>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "\n",
       "    <div>\n",
       "      <progress value='20' class='progress-bar-interrupted' max='30' style='width:300px; height:20px; vertical-align: middle;'></progress>\n",
       "      66.67% [20/30 04:33<02:16][earlystopping]\n",
       "    </div>\n",
       "    "
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "================================================================================2023-06-02 22:31:40\n",
      "Epoch 0 / 30\n",
      "\n",
      "100%|██████████████████| 100/100 [00:10<00:00,  9.51it/s, lr=0, train_acc=0.959, train_loss=0.00866]\n",
      "100%|███████████████████████████████| 20/20 [00:02<00:00,  8.41it/s, val_acc=0.956, val_loss=0.0106]\n",
      "\u001b[0;31m<<<<<< reach best val_acc : 0.95625 >>>>>>\u001b[0m\n",
      "\n",
      "================================================================================2023-06-02 22:31:54\n",
      "Epoch 1 / 30\n",
      "\n",
      "100%|████████████████| 100/100 [00:10<00:00,  9.35it/s, lr=2e-6, train_acc=0.957, train_loss=0.0104]\n",
      "100%|███████████████████████████████| 20/20 [00:02<00:00,  8.23it/s, val_acc=0.968, val_loss=0.0091]\n",
      "\u001b[0;31m<<<<<< reach best val_acc : 0.967578125 >>>>>>\u001b[0m\n",
      "\n",
      "================================================================================2023-06-02 22:32:08\n",
      "Epoch 2 / 30\n",
      "\n",
      "100%|███████████████| 100/100 [00:10<00:00,  9.12it/s, lr=2e-6, train_acc=0.955, train_loss=0.00994]\n",
      "100%|███████████████████████████████| 20/20 [00:02<00:00,  8.09it/s, val_acc=0.958, val_loss=0.0102]\n",
      "\n",
      "================================================================================2023-06-02 22:32:22\n",
      "Epoch 3 / 30\n",
      "\n",
      "100%|████████████████| 100/100 [00:11<00:00,  8.87it/s, lr=2e-6, train_acc=0.958, train_loss=0.0101]\n",
      "100%|██████████████████████████████| 20/20 [00:02<00:00,  7.28it/s, val_acc=0.961, val_loss=0.00812]\n",
      "\n",
      "================================================================================2023-06-02 22:32:36\n",
      "Epoch 4 / 30\n",
      "\n",
      "100%|████████████████| 100/100 [00:10<00:00,  9.33it/s, lr=2e-6, train_acc=0.958, train_loss=0.0103]\n",
      "100%|██████████████████████████████| 20/20 [00:02<00:00,  8.19it/s, val_acc=0.963, val_loss=0.00684]\n",
      "\n",
      "================================================================================2023-06-02 22:32:49\n",
      "Epoch 5 / 30\n",
      "\n",
      "100%|███████████████| 100/100 [00:10<00:00,  9.32it/s, lr=2e-6, train_acc=0.959, train_loss=0.00985]\n",
      "100%|██████████████████████████████| 20/20 [00:02<00:00,  8.51it/s, val_acc=0.966, val_loss=0.00762]\n",
      "\u001b[0;31m<<<<<< val_acc without improvement in 10 epoch,early stopping >>>>>>\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>epoch</th>\n",
       "      <th>train_loss</th>\n",
       "      <th>train_acc</th>\n",
       "      <th>lr</th>\n",
       "      <th>val_loss</th>\n",
       "      <th>val_acc</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0</td>\n",
       "      <td>0.008659</td>\n",
       "      <td>0.959375</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>0.010554</td>\n",
       "      <td>0.956250</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>0.010375</td>\n",
       "      <td>0.957031</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.009104</td>\n",
       "      <td>0.967578</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2</td>\n",
       "      <td>0.009938</td>\n",
       "      <td>0.955234</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.010214</td>\n",
       "      <td>0.957812</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>3</td>\n",
       "      <td>0.010119</td>\n",
       "      <td>0.957578</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.008124</td>\n",
       "      <td>0.960938</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>4</td>\n",
       "      <td>0.010345</td>\n",
       "      <td>0.957578</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.006836</td>\n",
       "      <td>0.962891</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>5</td>\n",
       "      <td>0.009854</td>\n",
       "      <td>0.959219</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.007617</td>\n",
       "      <td>0.965625</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>6</td>\n",
       "      <td>0.010075</td>\n",
       "      <td>0.958750</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.010425</td>\n",
       "      <td>0.951172</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>7</td>\n",
       "      <td>0.010189</td>\n",
       "      <td>0.958281</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.010673</td>\n",
       "      <td>0.954688</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>8</td>\n",
       "      <td>0.009672</td>\n",
       "      <td>0.957969</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.008521</td>\n",
       "      <td>0.962109</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>9</td>\n",
       "      <td>0.010017</td>\n",
       "      <td>0.961016</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.010152</td>\n",
       "      <td>0.957812</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>10</td>\n",
       "      <td>0.009575</td>\n",
       "      <td>0.959375</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.007342</td>\n",
       "      <td>0.968359</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>11</td>\n",
       "      <td>0.009236</td>\n",
       "      <td>0.956094</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.010885</td>\n",
       "      <td>0.960547</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>12</td>\n",
       "      <td>0.008944</td>\n",
       "      <td>0.962109</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.010604</td>\n",
       "      <td>0.957031</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>13</td>\n",
       "      <td>0.010579</td>\n",
       "      <td>0.956953</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.008698</td>\n",
       "      <td>0.965234</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>14</td>\n",
       "      <td>0.010503</td>\n",
       "      <td>0.955078</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.008728</td>\n",
       "      <td>0.961719</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>15</td>\n",
       "      <td>0.009218</td>\n",
       "      <td>0.961094</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.009786</td>\n",
       "      <td>0.956641</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>16</td>\n",
       "      <td>0.009576</td>\n",
       "      <td>0.959297</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.011156</td>\n",
       "      <td>0.954688</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>17</td>\n",
       "      <td>0.008933</td>\n",
       "      <td>0.957500</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.007454</td>\n",
       "      <td>0.963672</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>18</td>\n",
       "      <td>0.009990</td>\n",
       "      <td>0.957656</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.009762</td>\n",
       "      <td>0.966406</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>19</td>\n",
       "      <td>0.011394</td>\n",
       "      <td>0.955469</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.009925</td>\n",
       "      <td>0.958984</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>20</th>\n",
       "      <td>20</td>\n",
       "      <td>0.009683</td>\n",
       "      <td>0.959141</td>\n",
       "      <td>0.000002</td>\n",
       "      <td>0.007040</td>\n",
       "      <td>0.965625</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    epoch  train_loss  train_acc        lr  val_loss   val_acc\n",
       "0       0    0.008659   0.959375  0.000000  0.010554  0.956250\n",
       "1       1    0.010375   0.957031  0.000002  0.009104  0.967578\n",
       "2       2    0.009938   0.955234  0.000002  0.010214  0.957812\n",
       "3       3    0.010119   0.957578  0.000002  0.008124  0.960938\n",
       "4       4    0.010345   0.957578  0.000002  0.006836  0.962891\n",
       "5       5    0.009854   0.959219  0.000002  0.007617  0.965625\n",
       "6       6    0.010075   0.958750  0.000002  0.010425  0.951172\n",
       "7       7    0.010189   0.958281  0.000002  0.010673  0.954688\n",
       "8       8    0.009672   0.957969  0.000002  0.008521  0.962109\n",
       "9       9    0.010017   0.961016  0.000002  0.010152  0.957812\n",
       "10     10    0.009575   0.959375  0.000002  0.007342  0.968359\n",
       "11     11    0.009236   0.956094  0.000002  0.010885  0.960547\n",
       "12     12    0.008944   0.962109  0.000002  0.010604  0.957031\n",
       "13     13    0.010579   0.956953  0.000002  0.008698  0.965234\n",
       "14     14    0.010503   0.955078  0.000002  0.008728  0.961719\n",
       "15     15    0.009218   0.961094  0.000002  0.009786  0.956641\n",
       "16     16    0.009576   0.959297  0.000002  0.011156  0.954688\n",
       "17     17    0.008933   0.957500  0.000002  0.007454  0.963672\n",
       "18     18    0.009990   0.957656  0.000002  0.009762  0.966406\n",
       "19     19    0.011394   0.955469  0.000002  0.009925  0.958984\n",
       "20     20    0.009683   0.959141  0.000002  0.007040  0.965625"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.fit(\n",
    "    train_data = dl_train,\n",
    "    val_data= dl_val,\n",
    "    ckpt_path='ctc_crnn.pt',\n",
    "    epochs=30,\n",
    "    patience=10,\n",
    "    monitor=\"val_acc\", \n",
    "    mode=\"max\",\n",
    "    plot = True,\n",
    "    wandb = False,\n",
    "    callbacks=[visdis],\n",
    "    quiet = lambda epoch: epoch>5\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 四，评估模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2019-06-18T12:48:58.168479Z",
     "start_time": "2019-06-18T12:48:57.536996Z"
    },
    "code_folding": [
     3
    ]
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "a03593549a6e4c1db78b2580facb393f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Output()"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def display_fn(model):\n",
    "    model.eval()\n",
    "    right = True\n",
    "    while right:\n",
    "        image, target, input_length, label_length = ds_test[0]\n",
    "        output = model(image.unsqueeze(0).cuda())\n",
    "        output_argmax = output.detach().permute(1, 0, 2).argmax(dim=-1)\n",
    "        right = (decode_target(target) == decode(output_argmax[0]))\n",
    "        print('gt:', decode_target(target),' ','pred:', decode(output_argmax[0]))\n",
    "    display(to_pil_image(image))\n",
    "    \n",
    "    \n",
    "from torchkeras.kerascallbacks import VisDisplay\n",
    "visdis = VisDisplay(display_fn,model)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 五，使用模型\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "def predict(model,image):\n",
    "    model.cuda()\n",
    "    tensor = to_tensor(image)\n",
    "    output = model(tensor.unsqueeze(0).cuda())\n",
    "    output_argmax = output.detach().permute(1, 0, 2).argmax(dim=-1)\n",
    "    preds = decode(output_argmax[0])\n",
    "    return preds"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.load_ckpt('ctc_crnn.pt')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<PIL.Image.Image image mode=RGB size=192x64>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "'ABBD'"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "generator = ImageCaptcha(width=width, height=height)\n",
    "image = generator.generate_image('ABBD')\n",
    "display(image)\n",
    "predict(model,image)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 六，保存模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "torch.save(model.net.state_dict(),'best.pt')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**如果本项目对你有所帮助，想鼓励一下作者，记得给本项目加一颗星星star⭐️，并分享给你的朋友们喔😊!** \n",
    "\n",
    "如果在torchkeras的使用中遇到问题，可以在项目中提交issue。\n",
    "\n",
    "如果想要获得更快的反馈或者与其他torchkeras用户小伙伴进行交流，\n",
    "\n",
    "可以在公众号算法美食屋后台回复关键字：**加群**。\n",
    "\n",
    "![](https://tva1.sinaimg.cn/large/e6c9d24egy1h41m2zugguj20k00b9q46.jpg)"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Slideshow",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.0"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {
     "3e594ae65a88453682c6b98253d9a46f": {
      "model_module": "@jupyter-widgets/output",
      "model_module_version": "1.0.0",
      "model_name": "OutputModel",
      "state": {
       "layout": "IPY_MODEL_6a8e4a2263184121b6ce6dd5619e7112"
      }
     },
     "4e3c790e04ed41dc9653642087a09bde": {
      "model_module": "@jupyter-widgets/output",
      "model_module_version": "1.0.0",
      "model_name": "OutputModel",
      "state": {
       "layout": "IPY_MODEL_5698b97586c1475e857f3f74dbe1a9f0",
       "outputs": [
        {
         "data": {
          "text/html": "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #800000; text-decoration-color: #800000\">╭─────────────────────────────── </span><span style=\"color: #800000; text-decoration-color: #800000; font-weight: bold\">Traceback </span><span style=\"color: #bf7f7f; text-decoration-color: #bf7f7f; font-weight: bold\">(most recent call last)</span><span style=\"color: #800000; text-decoration-color: #800000\"> ────────────────────────────────╮</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/usr/local/lib/python3.8/dist-packages/torchkeras/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">kerascallbacks.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">243</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">__init__</span>              <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">240 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>display(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.out)                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">241 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">if</span> model <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">is</span> <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">not</span> <span style=\"color: #0000ff; text-decoration-color: #0000ff\">None</span>:                                                              <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">242 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">with</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.out:                                                                 <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span>243 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   │   </span><span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.display_fn(model)                                                     <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">244 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span>                                                                                       <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">245 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">def</span> <span style=\"color: #00ff00; text-decoration-color: #00ff00\">on_fit_start</span>(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>,model: <span style=\"color: #808000; text-decoration-color: #808000\">'KerasModel'</span>):                                            <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">246 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">pass</span>                                                                               <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">display_fn</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">6</span>                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 3 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span>right = <span style=\"color: #0000ff; text-decoration-color: #0000ff\">True</span>                                                                            <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 4 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">while</span> right:                                                                            <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 5 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>image, target, input_length, label_length = ds_test[<span style=\"color: #0000ff; text-decoration-color: #0000ff\">0</span>]                              <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span> 6 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>output = model(image.unsqueeze(<span style=\"color: #0000ff; text-decoration-color: #0000ff\">0</span>).cuda())                                           <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 7 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>output_argmax = output.detach().permute(<span style=\"color: #0000ff; text-decoration-color: #0000ff\">1</span>, <span style=\"color: #0000ff; text-decoration-color: #0000ff\">0</span>, <span style=\"color: #0000ff; text-decoration-color: #0000ff\">2</span>).argmax(dim=-<span style=\"color: #0000ff; text-decoration-color: #0000ff\">1</span>)                     <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 8 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>                                                                                    <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 9 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>right = (decode_target(target) == decode(output_argmax[<span style=\"color: #0000ff; text-decoration-color: #0000ff\">0</span>]))                         <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/usr/local/lib/python3.8/dist-packages/torch/nn/modules/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">module.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">1501</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">_call_impl</span>             <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1498 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">if</span> <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">not</span> (<span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>._backward_hooks <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>._backward_pre_hooks <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>._forward_hooks   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1499 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   │   </span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> _global_backward_pre_hooks <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> _global_backward_hooks                   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1500 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   │   </span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> _global_forward_hooks <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> _global_forward_pre_hooks):                   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span>1501 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">return</span> forward_call(*args, **kwargs)                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1502 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"># Do not call functions when jit is used</span>                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1503 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>full_backward_hooks, non_full_backward_hooks = [], []                             <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1504 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>backward_pre_hooks = []                                                           <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/usr/local/lib/python3.8/dist-packages/torchkeras/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">kerasmodel.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">114</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">forward</span>                   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">111 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.from_scratch = <span style=\"color: #0000ff; text-decoration-color: #0000ff\">False</span>                                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">112 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span>                                                                                       <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">113 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">def</span> <span style=\"color: #00ff00; text-decoration-color: #00ff00\">forward</span>(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>, x):                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span>114 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">return</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.net.forward(x)                                                         <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">115 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span>                                                                                       <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">116 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">def</span> <span style=\"color: #00ff00; text-decoration-color: #00ff00\">fit</span>(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>, train_data, val_data=<span style=\"color: #0000ff; text-decoration-color: #0000ff\">None</span>, epochs=<span style=\"color: #0000ff; text-decoration-color: #0000ff\">10</span>, ckpt_path=<span style=\"color: #808000; text-decoration-color: #808000\">'checkpoint.pt'</span>,         <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">117 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span>patience=<span style=\"color: #0000ff; text-decoration-color: #0000ff\">5</span>, monitor=<span style=\"color: #808000; text-decoration-color: #808000\">\"val_loss\"</span>, mode=<span style=\"color: #808000; text-decoration-color: #808000\">\"min\"</span>, callbacks=<span style=\"color: #0000ff; text-decoration-color: #0000ff\">None</span>, plot=<span style=\"color: #0000ff; text-decoration-color: #0000ff\">True</span>, wandb   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">forward</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">37</span>                                                                                    <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">34 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span>                                                                                        <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">35 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span>                                                                                        <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">36 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">def</span> <span style=\"color: #00ff00; text-decoration-color: #00ff00\">forward</span>(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>, x):                                                                   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span>37 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>x = <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.cnn(x)                                                                     <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">38 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>x = x.reshape(x.shape[<span style=\"color: #0000ff; text-decoration-color: #0000ff\">0</span>], -<span style=\"color: #0000ff; text-decoration-color: #0000ff\">1</span>, x.shape[-<span style=\"color: #0000ff; text-decoration-color: #0000ff\">1</span>])                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">39 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>x = x.permute(<span style=\"color: #0000ff; text-decoration-color: #0000ff\">2</span>, <span style=\"color: #0000ff; text-decoration-color: #0000ff\">0</span>, <span style=\"color: #0000ff; text-decoration-color: #0000ff\">1</span>)                                                              <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">40 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>x, _ = <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.lstm(x)                                                                 <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/usr/local/lib/python3.8/dist-packages/torch/nn/modules/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">module.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">1501</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">_call_impl</span>             <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1498 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">if</span> <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">not</span> (<span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>._backward_hooks <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>._backward_pre_hooks <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>._forward_hooks   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1499 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   │   </span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> _global_backward_pre_hooks <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> _global_backward_hooks                   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1500 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   │   </span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> _global_forward_hooks <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> _global_forward_pre_hooks):                   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span>1501 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">return</span> forward_call(*args, **kwargs)                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1502 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"># Do not call functions when jit is used</span>                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1503 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>full_backward_hooks, non_full_backward_hooks = [], []                             <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1504 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>backward_pre_hooks = []                                                           <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/usr/local/lib/python3.8/dist-packages/torch/nn/modules/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">container.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">217</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">forward</span>              <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">214 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"># with Any as TorchScript expects a more precise type</span>                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">215 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">def</span> <span style=\"color: #00ff00; text-decoration-color: #00ff00\">forward</span>(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">input</span>):                                                              <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">216 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">for</span> module <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">in</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>:                                                                <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span>217 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span><span style=\"color: #00ffff; text-decoration-color: #00ffff\">input</span> = module(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">input</span>)                                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">218 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">return</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff\">input</span>                                                                       <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">219 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span>                                                                                       <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">220 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">def</span> <span style=\"color: #00ff00; text-decoration-color: #00ff00\">append</span>(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>, module: Module) -&gt; <span style=\"color: #808000; text-decoration-color: #808000\">'Sequential'</span>:                                      <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/usr/local/lib/python3.8/dist-packages/torch/nn/modules/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">module.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">1501</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">_call_impl</span>             <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1498 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">if</span> <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">not</span> (<span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>._backward_hooks <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>._backward_pre_hooks <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>._forward_hooks   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1499 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   │   </span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> _global_backward_pre_hooks <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> _global_backward_hooks                   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1500 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   │   </span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> _global_forward_hooks <span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">or</span> _global_forward_pre_hooks):                   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span>1501 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">return</span> forward_call(*args, **kwargs)                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1502 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"># Do not call functions when jit is used</span>                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1503 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>full_backward_hooks, non_full_backward_hooks = [], []                             <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">1504 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span>backward_pre_hooks = []                                                           <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/usr/local/lib/python3.8/dist-packages/torch/nn/modules/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">conv.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">463</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">forward</span>                   <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 460 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   │   │   │   </span><span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.padding, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.dilation, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.groups)                         <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 461 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span>                                                                                      <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 462 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">def</span> <span style=\"color: #00ff00; text-decoration-color: #00ff00\">forward</span>(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">input</span>: Tensor) -&gt; Tensor:                                           <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span> 463 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">return</span> <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>._conv_forward(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">input</span>, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.weight, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.bias)                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 464 </span>                                                                                          <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 465 </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">class</span> <span style=\"color: #00ff00; text-decoration-color: #00ff00; text-decoration: underline\">Conv3d</span>(_ConvNd):                                                                    <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 466 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #ff0000; text-decoration-color: #ff0000\">__doc__</span> = <span style=\"color: #808000; text-decoration-color: #808000\">r\"\"\"Applies a 3D convolution over an input signal composed of several inpu</span>  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #bfbf7f; text-decoration-color: #bfbf7f\">/usr/local/lib/python3.8/dist-packages/torch/nn/modules/</span><span style=\"color: #808000; text-decoration-color: #808000; font-weight: bold\">conv.py</span>:<span style=\"color: #0000ff; text-decoration-color: #0000ff\">459</span> in <span style=\"color: #00ff00; text-decoration-color: #00ff00\">_conv_forward</span>             <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>                                                                                                  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 456 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">return</span> F.conv2d(F.pad(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">input</span>, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>._reversed_padding_repeated_twice, mode=<span style=\"color: #00ffff; text-decoration-color: #00ffff\">sel</span>  <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 457 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   │   │   │   │   </span>weight, bias, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.stride,                                    <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 458 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   │   │   │   │   </span>_pair(<span style=\"color: #0000ff; text-decoration-color: #0000ff\">0</span>), <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.dilation, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.groups)                         <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span> <span style=\"color: #800000; text-decoration-color: #800000\">❱ </span> 459 <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">return</span> F.conv2d(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">input</span>, weight, bias, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.stride,                                 <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 460 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   │   │   │   │   │   </span><span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.padding, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.dilation, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>.groups)                         <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 461 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span>                                                                                      <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">│</span>   <span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\"> 462 </span><span style=\"color: #7f7f7f; text-decoration-color: #7f7f7f\">│   </span><span style=\"color: #0000ff; text-decoration-color: #0000ff\">def</span> <span style=\"color: #00ff00; text-decoration-color: #00ff00\">forward</span>(<span style=\"color: #00ffff; text-decoration-color: #00ffff\">self</span>, <span style=\"color: #00ffff; text-decoration-color: #00ffff\">input</span>: Tensor) -&gt; Tensor:                                           <span style=\"color: #800000; text-decoration-color: #800000\">│</span>\n<span style=\"color: #800000; text-decoration-color: #800000\">╰──────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n<span style=\"color: #ff0000; text-decoration-color: #ff0000; font-weight: bold\">RuntimeError: </span>Input type <span style=\"font-weight: bold\">(</span>torch.cuda.FloatTensor<span style=\"font-weight: bold\">)</span> and weight type <span style=\"font-weight: bold\">(</span>torch.FloatTensor<span style=\"font-weight: bold\">)</span> should be the same\n</pre>\n",
          "text/plain": "\u001b[31m╭─\u001b[0m\u001b[31m──────────────────────────────\u001b[0m\u001b[31m \u001b[0m\u001b[1;31mTraceback \u001b[0m\u001b[1;2;31m(most recent call last)\u001b[0m\u001b[31m \u001b[0m\u001b[31m───────────────────────────────\u001b[0m\u001b[31m─╮\u001b[0m\n\u001b[31m│\u001b[0m \u001b[2;33m/usr/local/lib/python3.8/dist-packages/torchkeras/\u001b[0m\u001b[1;33mkerascallbacks.py\u001b[0m:\u001b[94m243\u001b[0m in \u001b[92m__init__\u001b[0m              \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m240 \u001b[0m\u001b[2m│   │   \u001b[0mdisplay(\u001b[96mself\u001b[0m.out)                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m241 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[94mif\u001b[0m model \u001b[95mis\u001b[0m \u001b[95mnot\u001b[0m \u001b[94mNone\u001b[0m:                                                              \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m242 \u001b[0m\u001b[2m│   │   │   \u001b[0m\u001b[94mwith\u001b[0m \u001b[96mself\u001b[0m.out:                                                                 \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m243 \u001b[2m│   │   │   │   \u001b[0m\u001b[96mself\u001b[0m.display_fn(model)                                                     \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m244 \u001b[0m\u001b[2m│   \u001b[0m                                                                                       \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m245 \u001b[0m\u001b[2m│   \u001b[0m\u001b[94mdef\u001b[0m \u001b[92mon_fit_start\u001b[0m(\u001b[96mself\u001b[0m,model: \u001b[33m'\u001b[0m\u001b[33mKerasModel\u001b[0m\u001b[33m'\u001b[0m):                                            \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m246 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[94mpass\u001b[0m                                                                               \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m in \u001b[92mdisplay_fn\u001b[0m:\u001b[94m6\u001b[0m                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 3 \u001b[0m\u001b[2m│   \u001b[0mright = \u001b[94mTrue\u001b[0m                                                                            \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 4 \u001b[0m\u001b[2m│   \u001b[0m\u001b[94mwhile\u001b[0m right:                                                                            \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 5 \u001b[0m\u001b[2m│   │   \u001b[0mimage, target, input_length, label_length = ds_test[\u001b[94m0\u001b[0m]                              \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m 6 \u001b[2m│   │   \u001b[0moutput = model(image.unsqueeze(\u001b[94m0\u001b[0m).cuda())                                           \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 7 \u001b[0m\u001b[2m│   │   \u001b[0moutput_argmax = output.detach().permute(\u001b[94m1\u001b[0m, \u001b[94m0\u001b[0m, \u001b[94m2\u001b[0m).argmax(dim=-\u001b[94m1\u001b[0m)                     \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 8 \u001b[0m\u001b[2m│   │   \u001b[0m                                                                                    \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 9 \u001b[0m\u001b[2m│   │   \u001b[0mright = (decode_target(target) == decode(output_argmax[\u001b[94m0\u001b[0m]))                         \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[2;33m/usr/local/lib/python3.8/dist-packages/torch/nn/modules/\u001b[0m\u001b[1;33mmodule.py\u001b[0m:\u001b[94m1501\u001b[0m in \u001b[92m_call_impl\u001b[0m             \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1498 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[94mif\u001b[0m \u001b[95mnot\u001b[0m (\u001b[96mself\u001b[0m._backward_hooks \u001b[95mor\u001b[0m \u001b[96mself\u001b[0m._backward_pre_hooks \u001b[95mor\u001b[0m \u001b[96mself\u001b[0m._forward_hooks   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1499 \u001b[0m\u001b[2m│   │   │   │   \u001b[0m\u001b[95mor\u001b[0m _global_backward_pre_hooks \u001b[95mor\u001b[0m _global_backward_hooks                   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1500 \u001b[0m\u001b[2m│   │   │   │   \u001b[0m\u001b[95mor\u001b[0m _global_forward_hooks \u001b[95mor\u001b[0m _global_forward_pre_hooks):                   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m1501 \u001b[2m│   │   │   \u001b[0m\u001b[94mreturn\u001b[0m forward_call(*args, **kwargs)                                          \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1502 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[2m# Do not call functions when jit is used\u001b[0m                                          \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1503 \u001b[0m\u001b[2m│   │   \u001b[0mfull_backward_hooks, non_full_backward_hooks = [], []                             \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1504 \u001b[0m\u001b[2m│   │   \u001b[0mbackward_pre_hooks = []                                                           \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[2;33m/usr/local/lib/python3.8/dist-packages/torchkeras/\u001b[0m\u001b[1;33mkerasmodel.py\u001b[0m:\u001b[94m114\u001b[0m in \u001b[92mforward\u001b[0m                   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m111 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[96mself\u001b[0m.from_scratch = \u001b[94mFalse\u001b[0m                                                          \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m112 \u001b[0m\u001b[2m│   \u001b[0m                                                                                       \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m113 \u001b[0m\u001b[2m│   \u001b[0m\u001b[94mdef\u001b[0m \u001b[92mforward\u001b[0m(\u001b[96mself\u001b[0m, x):                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m114 \u001b[2m│   │   \u001b[0m\u001b[94mreturn\u001b[0m \u001b[96mself\u001b[0m.net.forward(x)                                                         \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m115 \u001b[0m\u001b[2m│   \u001b[0m                                                                                       \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m116 \u001b[0m\u001b[2m│   \u001b[0m\u001b[94mdef\u001b[0m \u001b[92mfit\u001b[0m(\u001b[96mself\u001b[0m, train_data, val_data=\u001b[94mNone\u001b[0m, epochs=\u001b[94m10\u001b[0m, ckpt_path=\u001b[33m'\u001b[0m\u001b[33mcheckpoint.pt\u001b[0m\u001b[33m'\u001b[0m,         \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m117 \u001b[0m\u001b[2m│   │   │   \u001b[0mpatience=\u001b[94m5\u001b[0m, monitor=\u001b[33m\"\u001b[0m\u001b[33mval_loss\u001b[0m\u001b[33m\"\u001b[0m, mode=\u001b[33m\"\u001b[0m\u001b[33mmin\u001b[0m\u001b[33m\"\u001b[0m, callbacks=\u001b[94mNone\u001b[0m, plot=\u001b[94mTrue\u001b[0m, wandb   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m in \u001b[92mforward\u001b[0m:\u001b[94m37\u001b[0m                                                                                    \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m34 \u001b[0m\u001b[2m│   \u001b[0m                                                                                        \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m35 \u001b[0m\u001b[2m│   \u001b[0m                                                                                        \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m36 \u001b[0m\u001b[2m│   \u001b[0m\u001b[94mdef\u001b[0m \u001b[92mforward\u001b[0m(\u001b[96mself\u001b[0m, x):                                                                   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m37 \u001b[2m│   │   \u001b[0mx = \u001b[96mself\u001b[0m.cnn(x)                                                                     \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m38 \u001b[0m\u001b[2m│   │   \u001b[0mx = x.reshape(x.shape[\u001b[94m0\u001b[0m], -\u001b[94m1\u001b[0m, x.shape[-\u001b[94m1\u001b[0m])                                          \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m39 \u001b[0m\u001b[2m│   │   \u001b[0mx = x.permute(\u001b[94m2\u001b[0m, \u001b[94m0\u001b[0m, \u001b[94m1\u001b[0m)                                                              \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m40 \u001b[0m\u001b[2m│   │   \u001b[0mx, _ = \u001b[96mself\u001b[0m.lstm(x)                                                                 \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[2;33m/usr/local/lib/python3.8/dist-packages/torch/nn/modules/\u001b[0m\u001b[1;33mmodule.py\u001b[0m:\u001b[94m1501\u001b[0m in \u001b[92m_call_impl\u001b[0m             \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1498 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[94mif\u001b[0m \u001b[95mnot\u001b[0m (\u001b[96mself\u001b[0m._backward_hooks \u001b[95mor\u001b[0m \u001b[96mself\u001b[0m._backward_pre_hooks \u001b[95mor\u001b[0m \u001b[96mself\u001b[0m._forward_hooks   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1499 \u001b[0m\u001b[2m│   │   │   │   \u001b[0m\u001b[95mor\u001b[0m _global_backward_pre_hooks \u001b[95mor\u001b[0m _global_backward_hooks                   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1500 \u001b[0m\u001b[2m│   │   │   │   \u001b[0m\u001b[95mor\u001b[0m _global_forward_hooks \u001b[95mor\u001b[0m _global_forward_pre_hooks):                   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m1501 \u001b[2m│   │   │   \u001b[0m\u001b[94mreturn\u001b[0m forward_call(*args, **kwargs)                                          \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1502 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[2m# Do not call functions when jit is used\u001b[0m                                          \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1503 \u001b[0m\u001b[2m│   │   \u001b[0mfull_backward_hooks, non_full_backward_hooks = [], []                             \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1504 \u001b[0m\u001b[2m│   │   \u001b[0mbackward_pre_hooks = []                                                           \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[2;33m/usr/local/lib/python3.8/dist-packages/torch/nn/modules/\u001b[0m\u001b[1;33mcontainer.py\u001b[0m:\u001b[94m217\u001b[0m in \u001b[92mforward\u001b[0m              \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m214 \u001b[0m\u001b[2m│   \u001b[0m\u001b[2m# with Any as TorchScript expects a more precise type\u001b[0m                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m215 \u001b[0m\u001b[2m│   \u001b[0m\u001b[94mdef\u001b[0m \u001b[92mforward\u001b[0m(\u001b[96mself\u001b[0m, \u001b[96minput\u001b[0m):                                                              \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m216 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[94mfor\u001b[0m module \u001b[95min\u001b[0m \u001b[96mself\u001b[0m:                                                                \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m217 \u001b[2m│   │   │   \u001b[0m\u001b[96minput\u001b[0m = module(\u001b[96minput\u001b[0m)                                                          \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m218 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[94mreturn\u001b[0m \u001b[96minput\u001b[0m                                                                       \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m219 \u001b[0m\u001b[2m│   \u001b[0m                                                                                       \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m220 \u001b[0m\u001b[2m│   \u001b[0m\u001b[94mdef\u001b[0m \u001b[92mappend\u001b[0m(\u001b[96mself\u001b[0m, module: Module) -> \u001b[33m'\u001b[0m\u001b[33mSequential\u001b[0m\u001b[33m'\u001b[0m:                                      \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[2;33m/usr/local/lib/python3.8/dist-packages/torch/nn/modules/\u001b[0m\u001b[1;33mmodule.py\u001b[0m:\u001b[94m1501\u001b[0m in \u001b[92m_call_impl\u001b[0m             \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1498 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[94mif\u001b[0m \u001b[95mnot\u001b[0m (\u001b[96mself\u001b[0m._backward_hooks \u001b[95mor\u001b[0m \u001b[96mself\u001b[0m._backward_pre_hooks \u001b[95mor\u001b[0m \u001b[96mself\u001b[0m._forward_hooks   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1499 \u001b[0m\u001b[2m│   │   │   │   \u001b[0m\u001b[95mor\u001b[0m _global_backward_pre_hooks \u001b[95mor\u001b[0m _global_backward_hooks                   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1500 \u001b[0m\u001b[2m│   │   │   │   \u001b[0m\u001b[95mor\u001b[0m _global_forward_hooks \u001b[95mor\u001b[0m _global_forward_pre_hooks):                   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m1501 \u001b[2m│   │   │   \u001b[0m\u001b[94mreturn\u001b[0m forward_call(*args, **kwargs)                                          \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1502 \u001b[0m\u001b[2m│   │   \u001b[0m\u001b[2m# Do not call functions when jit is used\u001b[0m                                          \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1503 \u001b[0m\u001b[2m│   │   \u001b[0mfull_backward_hooks, non_full_backward_hooks = [], []                             \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m1504 \u001b[0m\u001b[2m│   │   \u001b[0mbackward_pre_hooks = []                                                           \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[2;33m/usr/local/lib/python3.8/dist-packages/torch/nn/modules/\u001b[0m\u001b[1;33mconv.py\u001b[0m:\u001b[94m463\u001b[0m in \u001b[92mforward\u001b[0m                   \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 460 \u001b[0m\u001b[2m│   │   │   │   │   │   \u001b[0m\u001b[96mself\u001b[0m.padding, \u001b[96mself\u001b[0m.dilation, \u001b[96mself\u001b[0m.groups)                         \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 461 \u001b[0m\u001b[2m│   \u001b[0m                                                                                      \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 462 \u001b[0m\u001b[2m│   \u001b[0m\u001b[94mdef\u001b[0m \u001b[92mforward\u001b[0m(\u001b[96mself\u001b[0m, \u001b[96minput\u001b[0m: Tensor) -> Tensor:                                           \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m 463 \u001b[2m│   │   \u001b[0m\u001b[94mreturn\u001b[0m \u001b[96mself\u001b[0m._conv_forward(\u001b[96minput\u001b[0m, \u001b[96mself\u001b[0m.weight, \u001b[96mself\u001b[0m.bias)                          \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 464 \u001b[0m                                                                                          \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 465 \u001b[0m\u001b[94mclass\u001b[0m \u001b[4;92mConv3d\u001b[0m(_ConvNd):                                                                    \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 466 \u001b[0m\u001b[2m│   \u001b[0m\u001b[91m__doc__\u001b[0m = \u001b[33mr\u001b[0m\u001b[33m\"\"\"\u001b[0m\u001b[33mApplies a 3D convolution over an input signal composed of several inpu\u001b[0m  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[2;33m/usr/local/lib/python3.8/dist-packages/torch/nn/modules/\u001b[0m\u001b[1;33mconv.py\u001b[0m:\u001b[94m459\u001b[0m in \u001b[92m_conv_forward\u001b[0m             \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m                                                                                                  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 456 \u001b[0m\u001b[2m│   │   │   \u001b[0m\u001b[94mreturn\u001b[0m F.conv2d(F.pad(\u001b[96minput\u001b[0m, \u001b[96mself\u001b[0m._reversed_padding_repeated_twice, mode=\u001b[96msel\u001b[0m  \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 457 \u001b[0m\u001b[2m│   │   │   │   │   │   │   \u001b[0mweight, bias, \u001b[96mself\u001b[0m.stride,                                    \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 458 \u001b[0m\u001b[2m│   │   │   │   │   │   │   \u001b[0m_pair(\u001b[94m0\u001b[0m), \u001b[96mself\u001b[0m.dilation, \u001b[96mself\u001b[0m.groups)                         \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m \u001b[31m❱ \u001b[0m 459 \u001b[2m│   │   \u001b[0m\u001b[94mreturn\u001b[0m F.conv2d(\u001b[96minput\u001b[0m, weight, bias, \u001b[96mself\u001b[0m.stride,                                 \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 460 \u001b[0m\u001b[2m│   │   │   │   │   │   \u001b[0m\u001b[96mself\u001b[0m.padding, \u001b[96mself\u001b[0m.dilation, \u001b[96mself\u001b[0m.groups)                         \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 461 \u001b[0m\u001b[2m│   \u001b[0m                                                                                      \u001b[31m│\u001b[0m\n\u001b[31m│\u001b[0m   \u001b[2m 462 \u001b[0m\u001b[2m│   \u001b[0m\u001b[94mdef\u001b[0m \u001b[92mforward\u001b[0m(\u001b[96mself\u001b[0m, \u001b[96minput\u001b[0m: Tensor) -> Tensor:                                           \u001b[31m│\u001b[0m\n\u001b[31m╰──────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n\u001b[1;91mRuntimeError: \u001b[0mInput type \u001b[1m(\u001b[0mtorch.cuda.FloatTensor\u001b[1m)\u001b[0m and weight type \u001b[1m(\u001b[0mtorch.FloatTensor\u001b[1m)\u001b[0m should be the same\n"
         },
         "metadata": {},
         "output_type": "display_data"
        }
       ]
      }
     },
     "510be2636c4c44a38286697b18de6e4f": {
      "model_module": "@jupyter-widgets/output",
      "model_module_version": "1.0.0",
      "model_name": "OutputModel",
      "state": {
       "layout": "IPY_MODEL_efacf291a20045beb309c934165cf437",
       "outputs": [
        {
         "name": "stdout",
         "output_type": "stream",
         "text": "gt: 8CGQ   pred: 8CGQ\ngt: K550   pred: K550\ngt: ZS3S   pred: ZS3S\ngt: LYE7   pred: LYE7\ngt: E1VQ   pred: E1VQ\ngt: YZH6   pred: YZH6\ngt: NZSH   pred: NZSH\ngt: B88R   pred: B88R\ngt: P4EM   pred: P4EM\ngt: GLJB   pred: GLJB\ngt: SBHF   pred: SBHF\ngt: AR2K   pred: AR2K\ngt: 2G2X   pred: 2G2X\ngt: 2LH6   pred: 2LH6\ngt: 3UMV   pred: 3UMV\ngt: VZOL   pred: VZ0L\n"
        },
        {
         "data": {
          "image/png": "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",
          "text/plain": "<PIL.Image.Image image mode=RGB size=192x64>"
         },
         "metadata": {},
         "output_type": "display_data"
        }
       ]
      }
     },
     "5698b97586c1475e857f3f74dbe1a9f0": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {}
     },
     "6a8e4a2263184121b6ce6dd5619e7112": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {}
     },
     "77120b4441ef4d7a97a8177aa8032cff": {
      "model_module": "@jupyter-widgets/output",
      "model_module_version": "1.0.0",
      "model_name": "OutputModel",
      "state": {
       "layout": "IPY_MODEL_840a34942db44bb38f69edd6dc6524c2"
      }
     },
     "840a34942db44bb38f69edd6dc6524c2": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {}
     },
     "efacf291a20045beb309c934165cf437": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {}
     }
    },
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
